#include "defs.h"
#include "filter.h"

BOOL OnGetFilterVersion
(
	const char * nativeFilename,
	Config_T ** configPtrPtr,
	HTTP_FILTER_VERSION * pVer
)
{
	try
	{
		//
		// Create the configuration
		//

		Config_T * configPtr = new Config_T(nativeFilename);
		*configPtrPtr = configPtr;

		//
		// Get the notification flags
		//

		HRESULT hr = configPtr->Clr.get_Instance()->Register((FilterEvent *)&pVer->dwFlags);
		if( FAILED(hr) )
		{
			throw Exception_T(hr, __FILE__, __LINE__, __FUNCSIG__,
				"Unable to register for the configured managed filter events");
		}

		//
		// Perform the normal ISAPI Filter startup
		//

		pVer->dwFilterVersion = HTTP_FILTER_REVISION;

		configPtr->SimpleContextFree = !(pVer->dwFlags & SF_NOTIFY_END_OF_NET_SESSION);
		pVer->dwFlags |= SF_NOTIFY_END_OF_NET_SESSION;

		pVer->dwFlags |= 
			SF_NOTIFY_SECURE_PORT			|
			SF_NOTIFY_NONSECURE_PORT		|
			SF_NOTIFY_ORDER_HIGH;

		if( HIWORD(pVer->dwServerFilterVersion) != 6 )
		{
			pVer->dwFlags &= ~SF_NOTIFY_READ_RAW_DATA;
		}

		return TRUE;
	}
	catch(Exception_T & exp)
	{
		SetLastError(exp.Code);
		return FALSE;
	}
	catch(std::bad_alloc &)
	{
		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
		return FALSE;
	}
}

IProxySession * GetSession
(
	Clr_T & clr, 
	PHTTP_FILTER_CONTEXT pFC
)
{
	if( !pFC->pFilterContext )
	{
		IProxySession * sessionPtr = 0;
		clr.get_Instance()->CreateSession(&sessionPtr);
		pFC->pFilterContext = (void*)sessionPtr;
	}

	return (IProxySession *)pFC->pFilterContext;
}

DWORD OnReadRawData
(
	Config_T * configPtr, 
	PHTTP_FILTER_CONTEXT pFC, 
	PHTTP_FILTER_RAW_DATA pRawData,
	DWORD dwNotifyType
)
{
	KodeIT_Web::FilterStatus status;

	configPtr->Clr.get_Instance()->OnRawData(
		GetSession(configPtr->Clr, pFC),
		(long)pFC, 
		(long)pRawData, 
		(KodeIT_Web::FilterEvent)dwNotifyType,
		pRawData->cbInData,
		&status);

	return status;
}

DWORD OnPreProcHeaders
(
	Config_T * configPtr, 
	PHTTP_FILTER_CONTEXT pFC, 
	PHTTP_FILTER_PREPROC_HEADERS pPreProcHeaders,
	DWORD dwNotifyType
)
{
	KodeIT_Web::FilterStatus status;

	configPtr->Clr.get_Instance()->OnPreProcHeaders(
		GetSession(configPtr->Clr, pFC),
		(long)pFC, 
		(long)pPreProcHeaders, 
		(KodeIT_Web::FilterEvent)dwNotifyType,
		&status);

	return status;
}

DWORD OnUrlMap
(
	Config_T * configPtr, 
	PHTTP_FILTER_CONTEXT pFC, 
	PHTTP_FILTER_URL_MAP pUrlMap,
	DWORD dwNotifyType
)
{
	KodeIT_Web::FilterStatus status;

	configPtr->Clr.get_Instance()->OnUrlMap(
		GetSession(configPtr->Clr, pFC),
		(long)pFC, 
		(long)pUrlMap, 
		(KodeIT_Web::FilterEvent)dwNotifyType,
		pUrlMap->pszURL ? lstrlenA(pUrlMap->pszURL) + 1 : 0,
		pUrlMap->cbPathBuff,
		&status);

	return status;
}

DWORD OnAuthentication
(
	Config_T * configPtr, 
	PHTTP_FILTER_CONTEXT pFC, 
	PHTTP_FILTER_AUTHENT pAuthEnt,
	DWORD dwNotifyType
)
{
	KodeIT_Web::FilterStatus status;

	configPtr->Clr.get_Instance()->OnAuthentication(
		GetSession(configPtr->Clr, pFC),
		(long)pFC, 
		(long)pAuthEnt, 
		(KodeIT_Web::FilterEvent)dwNotifyType,
		&status);

	return status;
}

DWORD OnAccessDenied
(
	Config_T * configPtr, 
	PHTTP_FILTER_CONTEXT pFC, 
	PHTTP_FILTER_ACCESS_DENIED pAccessDenied,
	DWORD dwNotifyType
)
{
	KodeIT_Web::FilterStatus status;

	configPtr->Clr.get_Instance()->OnAccessDenied(
		GetSession(configPtr->Clr, pFC),
		(long)pFC, 
		(long)pAccessDenied, 
		(KodeIT_Web::FilterEvent)dwNotifyType,
		pAccessDenied->pszURL ? lstrlenA(pAccessDenied->pszURL) + 1 : 0,
		pAccessDenied->pszPhysicalPath ? lstrlenA(pAccessDenied->pszPhysicalPath) + 1 : 0,
		(KodeIT_Web::AccessDeniedReason)pAccessDenied->dwReason,
		&status);

	return status;
}

DWORD OnAuthComplete
(
	Config_T * configPtr, 
	PHTTP_FILTER_CONTEXT pFC, 
	PHTTP_FILTER_AUTH_COMPLETE_INFO pAuthCompleteInfo,
	DWORD dwNotifyType
)
{
	HANDLE hToken;
	pAuthCompleteInfo->GetUserToken(pFC, &hToken);

	KodeIT_Web::FilterStatus status;

	configPtr->Clr.get_Instance()->OnAuthComplete(
		GetSession(configPtr->Clr, pFC),
		(long)pFC, 
		(long)pAuthCompleteInfo, 
		(KodeIT_Web::FilterEvent)dwNotifyType, 
		(long)hToken,
		&status);

	return status;
}

DWORD OnSendResponse
(
	Config_T * configPtr, 
	PHTTP_FILTER_CONTEXT pFC, 
	PHTTP_FILTER_SEND_RESPONSE pSendResponse,
	DWORD dwNotifyType
)
{
	KodeIT_Web::FilterStatus status;

	configPtr->Clr.get_Instance()->OnSendResponse(
		GetSession(configPtr->Clr, pFC),
		(long)pFC, 
		(long)pSendResponse, 
		(KodeIT_Web::FilterEvent)dwNotifyType,
		pSendResponse->HttpStatus,
		&status);

	return status;
}

DWORD OnSendRawData
(
	Config_T * configPtr, 
	PHTTP_FILTER_CONTEXT pFC, 
	PHTTP_FILTER_RAW_DATA pRawData,
	DWORD dwNotifyType
)
{
	KodeIT_Web::FilterStatus status;

	configPtr->Clr.get_Instance()->OnRawData(
		GetSession(configPtr->Clr, pFC),
		(long)pFC, 
		(long)pRawData, 
		(KodeIT_Web::FilterEvent)dwNotifyType,
		pRawData->cbInData,
		&status);

	return status;
}

DWORD OnEndOfRequest
(
	Config_T * configPtr, 
	PHTTP_FILTER_CONTEXT pFC,
	DWORD dwNotifyType
)
{
	KodeIT_Web::FilterStatus status;

	configPtr->Clr.get_Instance()->OnEndRequest(
		GetSession(configPtr->Clr, pFC),
		(long)pFC, 
		(KodeIT_Web::FilterEvent)dwNotifyType,
		&status);

	return status;
}

DWORD OnLog
(
	Config_T * configPtr, 
	PHTTP_FILTER_CONTEXT pFC, 
	PHTTP_FILTER_LOG pLog,
	DWORD dwNotifyType
)
{
	KodeIT_Web::FilterStatus status;

	configPtr->Clr.get_Instance()->OnLog(
		GetSession(configPtr->Clr, pFC),
		(long)pFC, 
		(long)pLog, 
		(KodeIT_Web::FilterEvent)dwNotifyType,
		pLog->pszClientHostName ? lstrlenA(pLog->pszClientHostName) + 1 : 0,
		pLog->pszClientUserName ? lstrlenA(pLog->pszClientUserName) + 1 : 0,
		pLog->pszServerName ? lstrlenA(pLog->pszServerName) + 1 : 0,
		pLog->pszOperation ? lstrlenA(pLog->pszOperation) + 1 : 0,
		pLog->pszTarget ? lstrlenA(pLog->pszTarget) + 1 : 0,
		pLog->pszParameters ? lstrlenA(pLog->pszParameters) + 1 : 0,
		pLog->dwHttpStatus,
		pLog->dwWin32Status,
		pLog->dwBytesSent,
		pLog->dwBytesRecvd,
		pLog->msTimeForProcessing,
		&status);

	return status;
}

DWORD OnEndOfNetSession
(
	Config_T * configPtr, 
	PHTTP_FILTER_CONTEXT pFC,
	DWORD dwNotifyType
)
{
	KodeIT_Web::FilterStatus status = FilterStatus_NextNotification;

	if( !configPtr->SimpleContextFree )
	{
		configPtr->Clr.get_Instance()->OnEndRequest(
			GetSession(configPtr->Clr, pFC),
			(long)pFC, 
			(KodeIT_Web::FilterEvent)dwNotifyType,
			&status);
	}

	if( pFC->pFilterContext )
	{
		IProxySession * sessionPtr = (IProxySession *)pFC->pFilterContext;
		pFC->pFilterContext = 0;

		if( sessionPtr )
		{
			sessionPtr->Release();
		}
	}

	return status;
}

BOOL OnTerminateFilter
(
	Config_T * configPtr
)
{
	if( configPtr )
	{
		configPtr->Clr.get_Instance()->Shutdown();
		delete configPtr;
		configPtr = 0;
	}

	return TRUE;
}